<?php

/**
 * 访问者模式（操作复杂对象结构）
 * 
 * 概述：提供一个作用于某对象结构中的各元素的操作表示，它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
 * 
 * 类型：行为类模式
 * 
 * 角色：
 *  1，抽象访问者。
 *  2，具体访问者。
 *  3，抽象元素。
 *  4，具体元素。
 *  5，对象结构。
 *  
 * 优点：
 * 
 * 缺点：
 * 
 */

/**
 * 抽象访问者
 */
interface Visitor
{
	public function visitConcreteElementA(ConcreteElementA $elementA);
	public function visitConcreteElementB(ConcreteElementB $elementB);
}

/**
 * 抽象元素
 */
interface Element
{
	public function accept(Visitor $visitor);
}

/**
 * 具体访问者
 */
class ConcreteVisitorA implements Visitor
{
	public function visitConcreteElementA(ConcreteElementA $elementA)
	{
		echo $elementA->getName() . ' visitd by ConcerteVisitorA <br />';
	}
	
	public function visitConcreteElementB(ConcreteElementB $elementB)
	{
		echo $elementB->getName() . ' visitd by ConcerteVisitorA <br />';
	}
}

/**
 * 具体访问者
 */
class ConcreteVisitorB implements Visitor
{
	public function visitConcreteElementA(ConcreteElementA $elementA)
	{
		echo $elementA->getName() . ' visitd by ConcerteVisitorB <br />';
	}
	
	public function visitConcreteElementB(ConcreteElementB $elementB)
	{
		echo $elementB->getName() . ' visitd by ConcerteVisitorB <br />';
	}
}

/**
 * 具体元素
 */
class ConcreteElementA implements Element
{
	private $_name;
 
    public function __construct($name) {
        $this->_name = $name;
    }
 
    public function getName() {
        return $this->_name;
    }
	
	public function accept(Visitor $visitor)
	{
		$visitor->visitConcreteElementA($this);
	}
}

/**
 * 具体元素
 */
class ConcreteElementB implements Element
{
	private $_name;
 
    public function __construct($name) {
        $this->_name = $name;
    }
 
    public function getName() {
        return $this->_name;
    }
	
	public function accept(Visitor $visitor)
	{
		$visitor->visitConcreteElementB($this);
	}
}

/**
 * 结构对象
 */
class ObjectStructure
{
	private $_elements;
	
	public function __construct()
	{
		$this->_elements = array();
	}
	
	public function attach(Element $element)
	{
		$this->_elements[] = $element;
	}
	
	public function detach(Element $element)
	{
		$index = array_search($this->_elements, $element);
		if ($index !== false) {
			unset($index);
		}
	}
	
	public function accept(Visitor $visitor)
	{
		foreach ($this->_elements as $element) {
			$element->accept($visitor);
		}
	}
}

class Client
{
	public static function main()
	{
		//结构对象
		$objectStructure = new ObjectStructure();
		
		//添加元素
		$elementA1 = new ConcreteElementA('elementA1');
		$elementA2 = new ConcreteElementA('elementA2');
		$elementA3 = new ConcreteElementA('elementA3');
		$elementB1 = new ConcreteElementB('elementB1');
		$elementB2 = new ConcreteElementB('elementB2');
		$elementB3 = new ConcreteElementB('elementB3');
		
		$objectStructure->attach($elementA1);
		$objectStructure->attach($elementA2);
		$objectStructure->attach($elementA3);
		$objectStructure->attach($elementB1);
		$objectStructure->attach($elementB2);
		$objectStructure->attach($elementB3);
		
		//具体范围者
		$visitorA = new ConcreteVisitorA();
		
		$objectStructure->accept($visitorA);
	}
}

Client::main();